#!/usr/bin/env python3
import os
import glob
import pandas as pd
from datetime import datetime, timedelta
from jinja2 import Template

# 基础目录配置
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
CONFIG_DIR = os.path.join(BASE_DIR, "config")
XUNJIAN_DIR = os.path.join(BASE_DIR, "xunjian")
HTML_DIR = os.path.join(BASE_DIR, "html_report")
DEVICE_HTML_DIR = os.path.join(HTML_DIR, "devices")
TEMPLATES_DIR = os.path.join(BASE_DIR, "templates")

# 设备配置文件路径
SERVER_INFO = os.path.join(CONFIG_DIR, "servers", "server_info.txt")
SW_INFO = os.path.join(CONFIG_DIR, "sws", "sw_info.txt")

# 创建输出目录
os.makedirs(HTML_DIR, exist_ok=True)
os.makedirs(DEVICE_HTML_DIR, exist_ok=True)

CSS_STYLE = """
<style>
:root {
  --primary: #3498db;
  --primary-dark: #2980b9;
  --success: #2ecc71;
  --success-dark: #27ae60;
  --warning: #f39c12;
  --warning-dark: #e67e22;
  --danger: #e74c3c;
  --danger-dark: #c0392b;
  --light: #ecf0f1;
  --dark: #2c3e50;
  --gray: #95a5a6;
}

body {
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  background-color: #f5f7fa;
  margin: 0;
  padding: 20px;
  color: #333;
  line-height: 1.6;
}

.dashboard {
  max-width: 1200px;
  margin: 0 auto;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
  padding: 20px;
}

.summary-card {
  display: inline-block;
  padding: 15px;
  border-radius: 5px;
  background: var(--primary);
  color: white;
  margin-right: 15px;
  text-align: center;
}

.summary-card .count {
  font-size: 24px;
  font-weight: bold;
  display: block;
}

.summary-card .label {
  font-size: 14px;
}

table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 20px;
}

th, td {
  padding: 12px;
  text-align: left;
  border-bottom: 1px solid #ddd;
}

th {
  background-color: var(--primary);
  color: white;
  position: sticky;
  top: 0;
}

tr:nth-child(even) {
  background-color: #f9f9f9;
}

tr:hover {
  background-color: #f1f1f1;
}

.status-badge {
  display: inline-block;
  padding: 3px 8px;
  border-radius: 12px;
  font-size: 12px;
  font-weight: 500;
  color: white;
}

.status-online {
  background-color: var(--success);
}

.status-warning {
  background-color: var(--warning);
}

.status-offline {
  background-color: var(--danger);
}

.btn {
  display: inline-block;
  padding: 8px 16px;
  border-radius: 4px;
  background-color: var(--primary);
  color: white;
  text-decoration: none;
  transition: background-color 0.3s;
}

.btn:hover {
  background-color: var(--primary-dark);
}

.container {
  max-width: 1200px;
  margin: 0 auto;
  background: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

.status-details {
  margin-top: 5px;
  font-size: 0.8em;
  color: #666;
}

.device-meta {
  margin: 15px 0;
  display: flex;
  gap: 20px;
}

.meta-item {
  display: flex;
  align-items: center;
  gap: 5px;
}

.device-data {
  margin-top: 20px;
}

.login-error {
  color: white;
  background-color: var(--danger);
  padding: 2px 5px;
  border-radius: 3px;
  font-weight: bold;
}

.no-data {
  color: var(--gray);
  font-style: italic;
}
</style>
"""

JS_SCRIPT = """
<script>
document.addEventListener('DOMContentLoaded', function() {
  // 表格排序功能
  document.querySelectorAll('th').forEach(th => {
    th.style.cursor = 'pointer';
    th.addEventListener('click', () => {
      const table = th.closest('table');
      const colIndex = Array.from(th.parentNode.children).indexOf(th);
      const rows = Array.from(table.querySelectorAll('tbody tr'));

      rows.sort((a, b) => {
        const aVal = a.children[colIndex].textContent.trim();
        const bVal = b.children[colIndex].textContent.trim();
        return aVal.localeCompare(bVal);
      });

      table.querySelector('tbody').append(...rows);
    });
  });
});
</script>
"""

def load_devices_from_config():
    """从配置文件加载设备列表"""
    devices = []

    print("\n=== 正在加载设备列表 ===")

    # 读取服务器设备（空格分隔格式）
    if os.path.exists(SERVER_INFO):
        print(f"读取服务器配置: {SERVER_INFO}")
        with open(SERVER_INFO, 'r', encoding='utf-8') as f:
            for line in f:
                line = line.strip()
                if line and not line.startswith('#'):
                    parts = line.split()
                    if parts:  # 确保不是空行
                        device_name = parts[0]
                        print(f" - 找到服务器设备: {device_name}")
                        devices.append({
                            'name': device_name,
                            'type': 'server',
                            'config_path': os.path.join(CONFIG_DIR, "servers", device_name)
                        })

    # 读取网络设备（CSV格式）
    if os.path.exists(SW_INFO):
        print(f"\n读取网络设备配置: {SW_INFO}")
        with open(SW_INFO, 'r', encoding='utf-8') as f:
            for line in f:
                line = line.strip()
                if line and not line.startswith('#'):
                    parts = [p.strip() for p in line.split(',')]
                    if parts:  # 确保不是空行
                        device_name = parts[0]
                        print(f" - 找到网络设备: {device_name}")
                        devices.append({
                            'name': device_name,
                            'type': 'switch',
                            'config_path': os.path.join(CONFIG_DIR, "sws", device_name)
                        })

    print(f"\n总共找到 {len(devices)} 个设备")
    return devices

def is_login_error(value):
    """检查是否是login error"""
    if pd.isna(value) or value == '':
        return False
    return 'login error' in str(value).lower()

def process_csv_file(csv_path):
    """处理单个CSV文件，返回处理后的DataFrame"""
    try:
        # 读取CSV文件，保留空字符串
        df = pd.read_csv(csv_path, keep_default_na=False, na_values=[])

        if df.empty:
            return df

        # 自动识别时间列
        time_col = next(
            (col for col in df.columns
             if any(kw in col.lower() for kw in ['时间', 'date', 'timestamp'])),
            None
        )

        # 处理时间列
        if time_col:
            # 确保时间列有有效值
            df[time_col] = df.apply(
                lambda row: row[time_col] if row[time_col] and not is_login_error(row[time_col])
                else datetime.fromtimestamp(os.path.getmtime(csv_path)).strftime("%Y-%m-%d %H:%M:%S"),
                axis=1
            )
            try:
                df[time_col] = pd.to_datetime(df[time_col])
            except:
                df[time_col] = datetime.fromtimestamp(os.path.getmtime(csv_path))

        return df

    except Exception as e:
        print(f"! 处理文件 {csv_path} 失败: {str(e)}")
        return pd.DataFrame()

def get_recent_data(device_name, days=7):
    """获取设备最近days天的数据"""
    print(f"\n正在获取设备 {device_name} 的数据...")
    end_date = datetime.now()
    start_date = end_date - timedelta(days=days-1)

    data_frames = []

    # 检查当前月份和上个月的数据
    for month_offset in [0, -1]:
        check_date = end_date + timedelta(days=30*month_offset)
        year_month = check_date.strftime("%Y/%m")
        csv_path = os.path.join(XUNJIAN_DIR, year_month, f"{device_name}.csv")
        print(f"检查路径: {csv_path}")

        if os.path.exists(csv_path):
            df = process_csv_file(csv_path)
            if not df.empty:
                print(f"找到 {len(df)} 条记录")
                # 过滤日期范围内的数据
                time_col = next(
                    (col for col in df.columns
                     if any(kw in col.lower() for kw in ['时间', 'date', 'timestamp'])),
                    None
                )
                if time_col and pd.api.types.is_datetime64_any_dtype(df[time_col]):
                    df = df[df[time_col] >= start_date]
                data_frames.append(df)

    if data_frames:
        combined_df = pd.concat(data_frames, ignore_index=True)
        # 去除完全重复的行
        return combined_df.drop_duplicates()
    return pd.DataFrame()

def highlight_cell(val):
    """根据单元格内容返回CSS类名"""
    if pd.isna(val) or val == '':
        return 'no-data'
    val = str(val).strip().lower()
    # 优先检查login error
    if 'login error' in val:
        return 'login-error'
    if val in ['down', 'fail', 'error', 'offline', '-', 'n/a']:
        return 'status-offline'
    elif val in ['up', 'ok', 'success', 'online']:
        return 'status-online'
    elif val in ['warning', 'degraded']:
        return 'status-warning'
    elif val.replace('.', '', 1).isdigit():
        return 'numeric'
    return ''

def determine_device_status(df):
    """根据最后一次巡检结果确定设备状态"""
    if df.empty:
        return 'unknown', ["无数据"], None, [], None

    # 自动识别时间列
    time_col = next(
        (col for col in df.columns
         if any(kw in col.lower() for kw in ['时间', 'date', 'timestamp'])),
        None
    )

    # 获取最后一条记录（最近一次巡检）
    last_row = df.iloc[-1]
    rows_data = []

    # 检查是否整行都是login error
    is_complete_login_error = all(
        str(val).lower() == 'login error'
        for col, val in last_row.items()
        if col != time_col and str(val).lower() not in ['', 'nan']
    )

    if is_complete_login_error:
        return 'offline', ["通信失败 (login error)"], time_col, [last_row.to_dict()], last_row.get(time_col, 'N/A')

    status = 'online'
    details = []
    row_data = {}

    # 处理时间列
    if time_col:
        row_data[time_col] = last_row[time_col]

    # 检查各指标状态（仅检查最后一条记录）
    for col in df.columns:
        if col == time_col:
            continue

        val = last_row[col]
        cell_status = highlight_cell(val)
        row_data[col] = val

        if cell_status == 'login-error':
            details.append(f"{col}: 通信失败")
            status = 'offline'
        elif cell_status == 'status-offline':
            details.append(f"{col}: 离线")
            status = 'offline'
        elif cell_status == 'status-warning' and status != 'offline':
            details.append(f"{col}: 警告")
            status = 'warning'

    return status, details, time_col, [row_data], last_row.get(time_col, 'N/A')

def generate_reports():
    """生成报告主函数"""
    print("=== 开始生成巡检报告 ===")
    devices = load_devices_from_config()
    device_reports = []

    for device in devices:
        df = get_recent_data(device['name'])
        if not df.empty:
            # 获取状态和最后检查时间
            status, status_details, time_col, rows_data, latest_check = determine_device_status(df)

            # 格式化最后检查时间
            if isinstance(latest_check, (pd.Timestamp, datetime)):
                latest_check = latest_check.strftime("%Y-%m-%d %H:%M:%S")

            # 准备数据用于模板渲染
            device_data = {
                'name': device['name'],
                'type': device['type'],
                'status': status,
                'status_details': status_details,
                'latest_check': latest_check,
                'columns': [col for col in df.columns if col != time_col],
                'time_column': time_col,
                'rows': df.to_dict('records')  # 保留所有记录用于展示
            }
            device_reports.append(device_data)
            print(f"已加载设备 {device['name']}，状态: {status}")
        else:
            device_data = {
                'name': device['name'],
                'type': device['type'],
                'status': 'unknown',
                'status_details': ["无巡检数据"],
                'latest_check': 'N/A',
                'columns': [],
                'time_column': None,
                'rows': []
            }
            device_reports.append(device_data)
            print(f"! 设备 {device['name']} 无有效数据")

    # ... [其余代码保持不变] ...

    # 加载模板
    with open(os.path.join(TEMPLATES_DIR, "index_template.html"), 'r', encoding='utf-8') as f:
        index_template = Template(f.read())

    with open(os.path.join(TEMPLATES_DIR, "device_detail_template.html"), 'r', encoding='utf-8') as f:
        detail_template = Template(f.read())

    # 生成主页
    index_path = os.path.join(HTML_DIR, "index.html")
    with open(index_path, 'w', encoding='utf-8') as f:
        f.write(index_template.render(
            devices=device_reports,
            total_devices=len(device_reports),
            style=CSS_STYLE,
            script=JS_SCRIPT,
            today=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        ))
    print(f"\n已生成主页: {index_path}")

    # 生成设备详情页 - 关键修改：传递str函数到模板
    for device in device_reports:
        detail_file = os.path.join(DEVICE_HTML_DIR, f"{device['name']}.html")
        with open(detail_file, 'w', encoding='utf-8') as f:
            f.write(detail_template.render(
                device=device,
                highlight_cell=highlight_cell,
                str=str,  # 传递str函数到模板
                style=CSS_STYLE,
                script=JS_SCRIPT
            ))
        print(f"已生成详情页: {detail_file}")

    print(f"\n=== 报告生成完成 ===")
    print(f"总设备数: {len(device_reports)}")
    print(f"正常设备: {sum(1 for d in device_reports if d['status'] == 'online')}")
    print(f"警告设备: {sum(1 for d in device_reports if d['status'] == 'warning')}")
    print(f"离线设备: {sum(1 for d in device_reports if d['status'] in ['offline', 'unknown'])}")

if __name__ == "__main__":
    generate_reports()
